#pragma once


#include <wtl/atlctrls.h>
#include "..\DataManager\ArticleManager.h"

class IArticleTitleListCallBack
{
public:
	virtual void OnClickTitle(int nId,LPCWSTR strTitle) = 0;
	virtual void OnOpenArticle(int nId) = 0;
};



class CArtcleTitleList : 
	public CWindowImpl<CArtcleTitleList, CListViewCtrl>
{
	typedef CWindowImpl<CArtcleTitleList, CListViewCtrl> _super;
public:
	DECLARE_WND_CLASS(_T("CArtcleTitleList"))
	
	CArtcleTitleList(): m_ArtList(NULL)
	{
		m_bDragging = FALSE;
		m_pHoverTip = 0;
	}
	virtual ~CArtcleTitleList()
	{
		if( NULL != m_ArtList)
		{

			POSITION Pos = m_ArtList->GetHeadPosition();

			do {
				Article* pArt= m_ArtList->GetNext(Pos);
				delete pArt;
			} while (Pos != NULL);   
			delete m_ArtList;
		}
	}

public:
	BEGIN_MSG_MAP(CArtcleTitleList)   
		MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnToolTipEvent)
		MSG_WM_MOUSEMOVE(OnMouseMove)
		MSG_WM_LBUTTONDOWN(OnLButtonDown)
		MSG_WM_LBUTTONUP(OnLButtonUp)
		MSG_WM_LBUTTONDBLCLK(OnLButtonDbClick)
		REFLECTED_NOTIFY_CODE_HANDLER(LVN_BEGINDRAG,OnLvnBeginDrag)
		DEFAULT_REFLECTION_HANDLER()
	END_MSG_MAP()  
	LRESULT OnLvnBeginDrag    (int nCode, LPNMHDR pnmh, BOOL& bHandled)
	{
		m_nDragIndex = ((NM_LISTVIEW *)pnmh)->iItem;
		POINT pt;
		pt.x = 8;
		pt.y = 8;
		m_pDragImage = CreateDragImage (m_nDragIndex, &pt);
		ATLASSERT (m_pDragImage);
		// changes the cursor to the drag image (DragMove() is still required in 
		// OnMouseMove())
		m_pDragImage.BeginDrag (0, CPoint (8, 8));
		m_pDragImage.DragEnter (GetDesktopWindow (), ((NM_LISTVIEW *)pnmh)->ptAction);
		// set dragging flag
		m_bDragging = TRUE;
		m_hDropItem = NULL;
		m_nDropIndex = -1;
		m_pDropWnd = this->m_hWnd;
		// capture all mouse messages
		SetCapture ();
		return 0L;
	}
	void CreateToolTip()
	{
		m_wndToolTip.Create(m_hWnd);

		CToolInfo ti(0, m_hWnd);
		m_wndToolTip.AddTool(ti);
		m_wndToolTip.Activate(TRUE);
		m_wndToolTip.SetMaxTipWidth(500);
		m_wndToolTip.SetDelayTime(TTDT_AUTOPOP,5*1000);
		m_wndToolTip.SetDelayTime(TTDT_INITIAL,500);
	}

	void SetCallback(IArticleTitleListCallBack* pCB)
	{
		m_pCB = pCB;
	}

	void OnLButtonDown(UINT uMsg, CPoint ptx)
	{
		BOOL	bHandle = FALSE;
		LVHITTESTINFO hti;
		hti.pt = ptx;
		SubItemHitTest( &hti );
		
		Article* pdata = GetItemParamData(hti.iItem);
	
		if (pdata!=NULL)
		{
			
			if (m_pCB)
			{
				m_pCB->OnClickTitle(pdata->iID,pdata->strTitle);
				//m_pCB->ClickCheck();
			}
		
		}
		/*CPoint pt (ptx);
			ClientToScreen (&pt);
			HWND pDropWnd = WindowFromPoint (pt);
			TCHAR szClassName[MAX_PATH] = { 0 };
			GetClassName(pDropWnd, szClassName, MAX_PATH);
		MessageBox(szClassName);*/
		SetMsgHandled(bHandle);
	}
	void OnLButtonDbClick(UINT uMsg, CPoint ptx)
	{
		BOOL	bHandle = FALSE;
		LVHITTESTINFO hti;
		hti.pt = ptx;
		SubItemHitTest( &hti );
		
		Article* pdata = GetItemParamData(hti.iItem);
	
		if (pdata!=NULL)
		{
			
			if (m_pCB)
			{
				m_pCB->OnOpenArticle(pdata->iID);
				//m_pCB->ClickCheck();
			}
		
		}
		
		SetMsgHandled(bHandle);
	}
	void OnLButtonUp(UINT uMsg, CPoint ptx)
	{
		if (m_bDragging)
		{
			// release mouse capture
			::ReleaseCapture ();
			m_bDragging = FALSE;
			// end dragging
			m_pDragImage.DragLeave (GetDesktopWindow ());
			m_pDragImage.EndDrag ();

			CPoint pt (ptx);
			ClientToScreen (&pt);
			HWND pDropWnd = WindowFromPoint (pt);
			ATLASSERT (pDropWnd);
			::ScreenToClient(pDropWnd,&pt);
			TCHAR szClassName[MAX_PATH] = { 0 };
			GetClassName(pDropWnd, szClassName, MAX_PATH);
			//MessageBox(szClassName);
			if ( _tcsicmp(szClassName, L"CKnowlTypeTree") == 0 )
			{			
				CArticleCategoryTree artTree; 
				artTree.Attach(pDropWnd);
				DropItemOnTree(artTree);
				artTree.Detach();
				artTree.m_hWnd = NULL;
				
			}
			//else if (pDropWnd->IsKindOf (RUNTIME_CLASS (CListCtrl)))
			else if (_tcsicmp(szClassName,WC_LISTVIEW) == 0)
			{			
				//DropItemOnList ((CListViewCtrl)pDropWnd);
			}
			// get the CWnd pointer of the window that is under the mouse cursor
			//CWnd* pDropWnd = WindowFromPoint (pt);
			//ATLASSERT (pDropWnd);
			//// if window is CTreeCtrl
			//if (pDropWnd->IsKindOf (RUNTIME_CLASS (CTreeCtrl)))
			//	DropItemOnTree ((CTreeCtrl*)pDropWnd);
			//// if window is CListCtrl
			//else if (pDropWnd->IsKindOf (RUNTIME_CLASS (CListCtrl)))
			//	DropItemOnList ((CListCtrl*)pDropWnd);
		}

	}

	Article* GetItemParamData(int index)
	{
		return (Article*)CListViewCtrl::GetItemData(index);
	}
	void InsertItemX(Article* param)
	{
		int i = CListViewCtrl::InsertItem( CListViewCtrl::GetItemCount(), param->strTitle);
		CListViewCtrl::SetItemData(i,(DWORD_PTR)param);
	}

	
	BOOL InitArray(const int nID,CString strType)
	{
		if( NULL != m_ArtList)
		{

			POSITION Pos = m_ArtList->GetHeadPosition();

			do {
				Article* pArt= m_ArtList->GetNext(Pos);
				delete pArt;
			} while (Pos != NULL);   
			delete m_ArtList;
		}
		ClearAll();
		if(strType == L"TAGS")
			m_ArtList = m_ArtManager.GetArticleListByTag(nID);
		else
			m_ArtList = m_ArtManager.GetArticleList(nID);
		if(NULL != m_ArtList)
		{
			POSITION Pos = m_ArtList->GetHeadPosition();
			do {
					Article* pArt= m_ArtList->GetNext(Pos);
					InsertItemX(pArt);
			} while (Pos != NULL); 
			return TRUE;
		}
		return FALSE;
	}
	
	void DropItemOnTree (CArticleCategoryTree& pDropTree)
	{
		// remove hilight from drop target
		pDropTree.SelectDropTarget (NULL);
		if(!m_hDropItem)
			return;
		/*CArticleCategoryTree* pTree = static_cast<CArticleCategoryTree*>(pDropTree);
		if(!pTree)
		{
			return;
		}*/
		Article* art = GetItemParamData(m_nDragIndex);
		pDropTree.AcceptDrag(m_hDropItem,art->iID );

		// insert item into CTreeCtrl
		//HTREEITEM hNewItem = pDropTree->InsertItem (&tvis);
		//ATLASSERT (hNewItem);
		// select the new item we just inserted
		//ATLVERIFY (pDropTree->SelectItem (hNewItem));
		// delete the original item (move operation)
		ATLVERIFY (DeleteItem (m_nDragIndex));
	}
	BOOL DeleteItem(int nItem)
	{
		return _super::DeleteItem(nItem);
	}

	void DeleteItem(LPDELETEITEMSTRUCT)
	{
		return;
	}

	void ClearAll()
	{
		_super::DeleteAllItems();
	};



	void OnMouseMove(UINT uMsg, CPoint ptx)
	{
		
		if (m_bDragging)
		{
			CPoint pt (ptx);
			ClientToScreen (&pt);
			// move the drag image
			ATLVERIFY (m_pDragImage.DragMove (pt));
			// unlock window updates
			ATLVERIFY (m_pDragImage.DragShowNolock (FALSE));

			// get the CWnd pointer of the window that is under the mouse cursor
			HWND pDropWnd = WindowFromPoint (pt);
			ATLASSERT (pDropWnd);
			// if we drag outside current window
			if (pDropWnd != m_pDropWnd)
			{
				// turn off hilight for drop target in tree control
				if (m_hDropItem)
				{
					(CTreeViewCtrl(m_pDropWnd)).SelectDropTarget (NULL);
					m_hDropItem = NULL;
				}
				// turn off hilight for drop target in list control
				if (m_nDropIndex != -1)
				{
					//CListCtrl* pList = (CListCtrl*)m_pDropWnd;
					ATLVERIFY ((CListViewCtrl(m_pDropWnd)).SetItemState (m_nDropIndex, 0, LVIS_DROPHILITED));
					// redraw item
					ATLVERIFY ((CListViewCtrl(m_pDropWnd)).RedrawItems (m_nDropIndex, m_nDropIndex));
					(CListViewCtrl(m_pDropWnd)).UpdateWindow ();
					m_nDropIndex = -1;
				}
			}

			// save current window pointer
			m_pDropWnd = pDropWnd;

			// convert from screen coordinates to drop target client coordinates
			//CWindow pWin = CWindow(pDropWnd);
			::ScreenToClient(pDropWnd,&pt);
			TCHAR szClassName[MAX_PATH] = { 0 };
			GetClassName(pDropWnd, szClassName, MAX_PATH);
			//MessageBox(szClassName);
			if ( _tcsicmp(szClassName, L"CKnowlTypeTree") == 0 )
			// if window is CTreeCtrl
			//if (pDropWnd->IsKindOf (RUNTIME_CLASS (CTreeCtrl)))
			//if(pWin.GetWndClassName() == WC_TREEVIEW)
			{			
				UINT uFlags;
				// get the item that is below cursor
				m_hDropItem = ((CTreeViewCtrl)pDropWnd).HitTest (pt, &uFlags);
				// highlight it
				((CTreeViewCtrl)pDropWnd).SelectDropTarget (m_hDropItem);
			}
			//else if (pDropWnd->IsKindOf (RUNTIME_CLASS (CListCtrl)))
			else if (_tcsicmp(szClassName, L"CArtcleTitleList") == 0)
			{			
				UINT uFlags;
				//CListCtrl* pList = (CListCtrl*)pDropWnd;

				// turn off hilight for previous drop target
				(CListViewCtrl(m_pDropWnd)).SetItemState (m_nDropIndex, 0, LVIS_DROPHILITED);
				// redraw previous item
				(CListViewCtrl(m_pDropWnd)).RedrawItems (m_nDropIndex, m_nDropIndex);
				
				// get the item that is below cursor
				m_nDropIndex = (CListViewCtrl(m_pDropWnd)).HitTest (pt, &uFlags);
				// highlight it
				(CListViewCtrl(m_pDropWnd)).SetItemState (m_nDropIndex, LVIS_DROPHILITED, LVIS_DROPHILITED);
				// redraw item
				(CListViewCtrl(m_pDropWnd)).RedrawItems (m_nDropIndex, m_nDropIndex);
				(CListViewCtrl(m_pDropWnd)).UpdateWindow ();
			}
			// lock window updates
			m_pDragImage.DragShowNolock (TRUE);
		}
		BOOL	bShowTip = FALSE;
		int	iItem = XBASE_HitTest(ptx);
		Article* pItemData = (Article*)XBASE_GetItemData(iItem);

		if (pItemData)
		{

			if ( ((DWORD)pItemData!=m_pHoverTip) )
			{
				CString	strInfo;
				strInfo.Append(pItemData->strTitle);

				m_wndToolTip.SetMaxTipWidth(500);
				m_wndToolTip.UpdateTipText((LPCTSTR)strInfo,m_hWnd);
				m_pHoverTip = (DWORD)pItemData;
			}
			bShowTip = TRUE;
			
		}
		if (!bShowTip)
		{
			if (m_pHoverTip!=0)
			{
				m_pHoverTip = 0;
				m_wndToolTip.UpdateTipText((LPCTSTR)NULL,m_hWnd);
				m_wndToolTip.Pop();
			}
		}
	}

	LRESULT OnToolTipEvent(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		if(m_wndToolTip.IsWindow())
		{
			MSG msg = { m_hWnd, uMsg, wParam, lParam };

			m_wndToolTip.RelayEvent(&msg);
		}

		SetMsgHandled(FALSE);

		return 0;
	}

	

	DWORD_PTR XBASE_GetItemData(int nItem)
	{

		return CListViewCtrl::GetItemData(nItem);
	}

	BOOL XBASE_GetItemRect(int i, LPRECT lprc)
	{
		return CListViewCtrl::GetItemRect(i,lprc,LVIR_BOUNDS);

	}

	int XBASE_HitTest(CPoint ptx)
	{
		LVHITTESTINFO hti;
		hti.pt = ptx;
		SubItemHitTest( &hti );
		return hti.iItem;
	}

	Article* GetDataInfo(int nItem)
	{
		Article*	pParam = (Article*)XBASE_GetItemData(nItem);

		if (pParam!=NULL)
			return pParam;
		else
			return NULL;
	}
	
protected:

	IArticleTitleListCallBack*	m_pCB;
	CToolTipCtrl		m_wndToolTip;
	DWORD				m_pHoverTip;
	ArticleList*		m_ArtList;
	CArticleManager		m_ArtManager;

	//CImageList	m_Image;
	CImageList m_pDragImage;
	BOOL		m_bDragging;
	int			m_nDragIndex, m_nDropIndex;
	HTREEITEM	m_hDropItem;
	HWND		m_pDropWnd;
};